package com.ming.common.dynamic;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.ivy.parser.bus.*;
import com.ming.common.beetl.util.BeetlSqlUtil;
import com.ming.common.init.LogInit;
import com.ming.common.liteflow.core.dynamic.IvyDynamicClass;
import com.ming.common.liteflow.core.exec.ELExecUtil;
import com.ming.common.util.FileUtil;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IvyCmpHelper {

    private static final Logger LOG = LoggerFactory.getLogger(IvyCmpHelper.class);

    // 版本缓存
    private static final Map<String, Integer> dynamicClassVersionMap = new HashMap<>();
    // 源码缓存
    private static final Map<String, String> dynamicClassSourceMap = new HashMap<>();
    // 类缓存
    private static final Map<String, Class<?>> dynamicClassMap = new HashMap<>();

    public static Map<String,Object> execCmp(IvyDynamicClass item, String el){
        Class<?> aClass = loadClass(item);
        // 判断是否有EL表达式
        boolean flag = StrUtil.isBlank(el);

        long ms = System.currentTimeMillis();
        String startKey = ms + LogInit.startKey;
        String endKey = ms + LogInit.endKey;
        LOG.info(startKey);

        String key = item.getClassType() + (item.getIsFallback() == null ? "" : item.getIsFallback().toString());
        LiteFlowNodeBuilder builder = LiteFlowNodeBuilder.createCommonNode();
        String cmpId = item.getSourceCmpId();
        switch (key){
            case "11":
            case "10":
                builder = LiteFlowNodeBuilder.createCommonNode();
                if(flag){
                    el = ELBusThen.node(cmpId).toEL();
                }
                break;//普通组件类
            case "21":
            case "20":
                builder = LiteFlowNodeBuilder.createSwitchNode();
                if(flag) {
                    el = ELBusSwitch.NEW().node(cmpId).defaultOpt("CommonCmp").toEL();
                }
                break;//选择组件类
            case "31":
            case "30":
                builder = LiteFlowNodeBuilder.createIfNode();
                if(flag) {
                    el = ELBusIf.NEW().node(cmpId, "CommonCmp", "CommonCmp").toEL();
                }
                break;//条件组件类
            case "41":
            case "40":
                builder = LiteFlowNodeBuilder.createForNode();
                if(flag) {
                    el = ELBusFor.node(cmpId).doOpt("CommonCmp").toEL();
                }
                break;//次数循环组件类
            case "51":
            case "50":
                builder = LiteFlowNodeBuilder.createWhileNode();
                if(flag) {
                    el = ELBusWhile.node(cmpId).doOpt("CommonCmp").toEL();
                }
                break;//条件循环组件类
            case "61":
            case "60":
                builder = LiteFlowNodeBuilder.createIteratorNode();
                if(flag) {
                    el = ELBusIterator.node(cmpId).doOpt("CommonCmp").toEL();
                }
                break;//迭代循环组件类
            case "71":
            case "70":
                builder = LiteFlowNodeBuilder.createBreakNode();
                if(flag) {
                    el = ELBusIf.NEW().node(cmpId, "CommonCmp", "CommonCmp").toEL();
                }
                break;//退出循环组件类
        }
        builder.setId(cmpId).setName(item.getClassName()).setLanguage("java").setClazz(aClass).build();
        String returnVal = ELExecUtil.exec(el,false);

        LOG.info(endKey);
        List<String> list = LogInit.logMap.get(endKey);
        while (list == null || list.isEmpty()) {
            list = LogInit.logMap.get(endKey);// 等待list不为空
            ThreadUtil.sleep(100);
        }
        LogInit.logMap.remove(endKey);
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("el", el);
        resultMap.put("returnVal", returnVal);
        resultMap.put("logStr", String.join(System.lineSeparator(),list));
        return resultMap;
    }

    public static Class<?> loadClass(IvyDynamicClass item){
        String beanName = item.getSourceClassName();
        Integer version = dynamicClassVersionMap.getOrDefault(beanName,0);
        String source = dynamicClassSourceMap.getOrDefault(beanName,null);
        // 源码相同，版本相同，直接返回
        if((source != null && source.equals(item.getSourceCode())) && (version != null && version.equals(item.getVersion()))){
            Class<?> aClass = dynamicClassMap.get(beanName);
            if(aClass == null){
                return putCmp(item);
            }
            return aClass;
        }
        if(!dynamicClassVersionMap.containsKey(beanName)){
            return putCmp(item);
        }
        version = version + 1;
        item.setVersion(version);
        BeetlSqlUtil.NEW().getDefaultSQLManager().lambdaQuery(IvyDynamicClass.class)
                .andEq(IvyDynamicClass::getId,item.getId())
                .updateSelective(item);

        return putCmp(item);
    }

    private static Class<?> putCmp(IvyDynamicClass item){
        String beanName = item.getSourceClassName();
        Integer version = item.getVersion();
        Class<?> aClass = compilerCmp(item);
        dynamicClassVersionMap.put(beanName,version);
        dynamicClassSourceMap.put(beanName,item.getSourceCode());
        dynamicClassMap.put(beanName,aClass);
        return aClass;
    }

    private static Class<?> compilerCmp(IvyDynamicClass ivyDynamicClass) {
        String root = ClassUtils.getDefaultClassLoader().getResource("").getPath();
        String className = ivyDynamicClass.getSourceClassName()+ivyDynamicClass.getVersion();
        if(StrUtil.isBlank(ivyDynamicClass.getPackagePath())){
            ivyDynamicClass.setPackagePath(getPackagePath(ivyDynamicClass.getSourceCode()));
        }
        String packagePath = String.join(File.separator,ivyDynamicClass.getPackagePath().split("\\."));
        String rootPath = root+packagePath;
        String forName = ivyDynamicClass.getPackagePath()+"."+className;
        String sourceCode = ivyDynamicClass.getSourceCode();

        Pattern pattern = Pattern.compile("class\\s+(\\w+)");
        Matcher matcher = pattern.matcher(sourceCode);
        sourceCode = matcher.replaceAll("class " + className);

        pattern = Pattern.compile("@LiteflowComponent\\(\"([^\"]+)\"\\)");
        matcher = pattern.matcher(sourceCode);
        sourceCode = matcher.replaceAll("@LiteflowComponent(\"" + className+"\")");
        sourceCode = sourceCode.replaceAll(ivyDynamicClass.getSourceClassName()+".class",className+".class");

        Class<?> dynamicClass = null;
        try {
            // 检查并创建根路径
            File rootDir = new File(rootPath);
            if (!rootDir.exists()) {
                if (!rootDir.mkdirs()) {
                    System.err.println("无法创建动态class目录");
                    System.exit(1);
                }
            }

            String fileClassName = className + ".class";
            String fileJavaName = className + ".java";
            FileUtil.removeFile(rootPath,fileClassName,fileJavaName);

            // 确保输出目录存在
            File outputDir = new File(root);

            // 保存源码到文件
            File sourceFile = new File(rootDir, className + ".java");
            FileWriter writer = new FileWriter(sourceFile);
            writer.write(sourceCode);
            writer.close();

            // 获取系统编译器
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

            // 获取文件管理器
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

            // 获取编译单元
            Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile));

            // 设置编译参数
            Iterable<String> options = Arrays.asList("-d", outputDir.getAbsolutePath());

            // 创建编译任务
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);

            // 执行编译任务
            boolean success = task.call();

            if (success) {
                // 加载编译后的类
                URLClassLoader classLoader = new URLClassLoader(new URL[]{new File(root).toURI().toURL()});
                dynamicClass = Class.forName(forName, true, classLoader);

                // 创建实例并调用方法
                //Object instance = dynamicHelloClass.getDeclaredConstructor().newInstance();
                //dynamicHelloClass.getMethod(methodName).invoke(instance);
            }

            // 关闭文件管理器
            fileManager.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dynamicClass;
    }

    private static String getPackagePath(String sourceCode){
        // 定义正则表达式匹配包名
        String packageNameRegex = "\\bpackage\\s+([\\w.]+)\\s*;";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(packageNameRegex);
        // 创建 Matcher 对象并匹配源代码
        Matcher matcher = pattern.matcher(sourceCode);
        // 提取包名
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }
}
